<template>
  <div class="ebook-reader">
    <div id="read"></div>
    <div class="ebook-reader-mask"
      @click="onMaskClick"
      @touchmove="move"
      @touchend="moveEnd"
      @mousedown.left="onMouseEnter"
      @mousemove.left="onMouseMove"
      @mouseup.left="onMouseEnd"
    ></div>
  </div>
</template>

<script>
import Epub from 'epubjs'
import { ebookMixin } from '@/utils/mixin.js'
import { flatten } from '@/utils/book.js'
import {
  getFontFamily,
  saveFontFamily,
  getFontSize,
  saveFontSize,
  getTheme,
  saveTheme,
  getLocation
} from '@/utils/localStorage.js'

global.ePub = Epub

export default {
  data () {
    return {
      mouseState: null // 鼠标状态
    }
  },
  mixins: [ebookMixin],
  methods: {
    /*
      鼠标事件四个阶段
      1.鼠标进入
      2.鼠标进入后的移动
      3.鼠标从移动状态松手
      4.鼠标还原
    */
    // 鼠标抬起
    onMouseEnd (e) {
      if (this.mouseState === 2) {
        this.setOffsetY(0)
        this.firstOffsetY = null
        this.mouseState = 3
      } else {
        this.mouseState = 4
      }
      const time = e.timeStamp - this.mouseStartTime
      if (time < 150) {
        this.mouseState = 4
      }
      e.preventDefault()
      e.stopPropagation()
    },
    // 鼠标按下时
    onMouseEnter (e) {
      this.mouseState = 1
      this.mouseStartTime = e.timeStamp // 记录鼠标按下到抬起时的时间差，轻微移动也算点击
      e.preventDefault()
      e.stopPropagation()
    },
    // 鼠标移动
    onMouseMove (e) {
      if (this.mouseState === 1) {
        this.mouseState = 2
      } else if (this.mouseState === 2) {
        // 开始执行下拉
        let offsetY = 0
        if (this.firstOffsetY) {
          offsetY = e.clientY - this.firstOffsetY
          this.setOffsetY(offsetY)
        } else {
          this.firstOffsetY = e.clientY
        }
      }
      e.preventDefault()
      e.stopPropagation()
    },
    move (e) {
      let offsetY = 0
      if (this.firstOffsetY) {
        offsetY = e.changedTouches[0].clientY - this.firstOffsetY
        this.setOffsetY(offsetY)
      } else {
        this.firstOffsetY = e.changedTouches[0].clientY
      }
      e.preventDefault()
      e.stopPropagation()
    },
    moveEnd (e) {
      this.setOffsetY(0)
      this.firstOffsetY = null
    },
    onMaskClick (e) {
      if (this.mouseState && (this.mouseState === 2 || this.mouseState === 3)) {
        return
      }
      const offsetX = e.offsetX
      const width = window.innerWidth
      if (offsetX > 0 && offsetX < width * 0.3) {
        this.prevPage()
      } else if (offsetX > 0 && offsetX > width * 0.7) {
        this.nextPage()
      } else {
        this.toggleTitleAndMenu()
      }
    },
    prevPage () {
      if (this.rendition) {
        this.rendition.prev().then(() => {
          this.refreshLocation()
        })
        this.hideTitleAndMenu()
      }
    },
    nextPage () {
      if (this.rendition) {
        this.rendition.next().then(() => {
          this.refreshLocation()
        })
        this.hideTitleAndMenu()
      }
    },
    toggleTitleAndMenu () {
      if (this.menuVisible) {
        this.setSettingVisible(-1)
        this.setFontFamilyVisible(false)
      }
      this.setMenuVisible(!this.menuVisible)
    },
    initFontFamily () {
      // 字体初始化
      let font = getFontFamily(this.fileName)
      // 如果不能获取到字体缓存，就将默认字体缓存
      if (!font) {
        saveFontFamily(this.fileName, this.defaultFontFamily)
      } else {
        this.rendition.themes.font(font) // 设置阅读器的字体
        this.setDefaultFontFamily(font) // 设置 vuex 中的字体
      }
    },
    initFontSize () {
      // 字号初始化
      let fontSize = getFontSize(this.fileName)
      // 如果不能获取到字体缓存，就将默认字体缓存
      if (!fontSize) {
        saveFontSize(this.fileName, this.defaultFontSize)
      } else {
        this.rendition.themes.fontSize(`${fontSize}px`) // 设置阅读器的字号
        this.setDefaultFontSize(fontSize) // 设置 vuex 中的字体
      }
    },
    initRendition () {
      // 使用 epub 的渲染方法，渲染电子书
      this.rendition = this.book.renderTo('read', {
        width: innerWidth,
        height: innerHeight,
        methods: 'default'
        // flow: 'scrolled' // 切换成滚动条阅读模式，需要把上面的 methods: 'default' 注释掉，滚动模式在微信浏览器内存在bug
      })
      // 显示电子书
      const location = getLocation(this.fileName)
      this.display(location, () => {
        this.initTheme()
        this.initFontSize()
        this.initFontFamily()
        this.initGlobalStyle()
      })
      // 使用 epub 的方法给阅读器生成的 iframe 注入 css
      this.rendition.hooks.content.register((contents) => {
        // 使用 ES6 的 Promise.all 将多个 Promise 对象进行传入
        Promise.all([
          contents.addStylesheet(`${process.env.VUE_APP_RESOURCE_URL}/fonts/cabin.css`),
          contents.addStylesheet(`${process.env.VUE_APP_RESOURCE_URL}/fonts/daysOne.css`),
          contents.addStylesheet(`${process.env.VUE_APP_RESOURCE_URL}/fonts/montserrat.css`),
          contents.addStylesheet(`${process.env.VUE_APP_RESOURCE_URL}/fonts/tangerine.css`)
        ]).then(() => {
          // 数组中的 Promise 对象全部执行完成后，执行下面的语句
          console.log('字体全部加载完成')
        })
      })
    },
    // 绑定手势操作
    initGesture () {
      // 使用 epub 的 on 方法给 epub 生成的 iframe 绑定事件
      this.rendition.on('touchstart', event => {
        this.touchStartX = event.changedTouches[0].clientX
        this.touchStartTime = event.timeStamp
      })
      this.rendition.on('touchend', event => {
        const offsetX = event.changedTouches[0].clientX - this.touchStartX // 滑动距离
        const time = event.timeStamp - this.touchStartTime // 滑动间隔
        if (time < 500 && offsetX > 40) {
          this.prevPage()
        } else if (time < 500 && offsetX < -40) {
          this.nextPage()
        } else {
          this.toggleTitleAndMenu()
        }
        // event.preventDefault()
        event.stopPropagation() // 停止事件的传播
      })
    },
    parseBook () {
      // 获取电子书的封面图片
      this.book.loaded.cover.then(cover => {
        this.book.archive.createUrl(cover).then(url => {
          this.setCover(url)
        })
      })
      // 获取作者信息
      this.book.loaded.metadata.then(metadata => {
        this.setMetadata(metadata)
      })
      // 获取电子书的目录
      this.book.loaded.navigation.then(nav => {
        const navItem = flatten(nav.toc)
        function find (item, level = 0) {
          return !item.parent ? level : find(navItem.filter(parentItem => parentItem.id === item.parent)[0], ++level)
        }
        navItem.forEach(item => {
          item.level = find(item)
        })
        this.setNavigation(navItem)
      })
    },
    // 加载阅读器主题
    initTheme () {
      let dafaultTheme = getTheme(this.fileName)
      if (!dafaultTheme) {
        dafaultTheme = this.themeList[0].name
        saveTheme(this.fileName, dafaultTheme)
      }
      this.setDefaultTheme(dafaultTheme)
      // 注册阅读器主题
      this.themeList.forEach(theme => {
        this.rendition.themes.register(theme.name, theme.style)
      })
      this.rendition.themes.select(dafaultTheme)
    },
    initEpub () {
      const url = `${process.env.VUE_APP_RESOURCE_URL}/epub/` + this.fileName + '.epub'
      this.book = new Epub(url) // 实例化 epub 对象
      this.setCurrentBook(this.book) // 将当前 epub 对象挂载到 vuex
      this.initRendition() // 初始化渲染epub
      this.initGesture() // 初始化手势事件
      this.parseBook() // 解析电子书
      // epub 绑定分页，ready将在book全部解析完成后调用
      this.book.ready.then(() => {
        // 参数为需要分页的，每页文字数，默认150
        return this.book.locations.generate(750 * (window.innerWidth / 375) * getFontSize(this.fileName) / 16)
      }).then(locations => {
        this.navigation.forEach(nav => {
          nav.pagelist = []
        })
        locations.forEach(item => {
          const loc = item.match(/\[(.*)\]/)[1]
          this.navigation.forEach(nav => {
            if (nav.href) {
              const href = nav.href.match(/^(.*)\.html$/)[1]
              if (href === loc) {
                nav.pagelist.push(item)
              }
            }
          })
          let currentPage = 1
          this.navigation.forEach((nav, index) => {
            if (index === 0) {
              nav.page = 1
            } else {
              nav.page = currentPage
            }
            currentPage += nav.pagelist.length + 1
          })
        })
        this.setPagelist(locations)
        this.setBookAvailable(true) // 将电子书展示
        this.refreshLocation()
      })
    }
  },
  mounted () {
    const fileName = this.$route.params.fileName.split('|').join('/') // 获取动态路由的路径
    this.setFileName(fileName).then(() => {
      this.initEpub()
    })
  }
}
</script>

<style lang="scss" rel="stylesheet/scss" scoped>
.ebook-reader {
  width: 100%;
  height: 100%;
  overflow: hidden;
  .ebook-reader-mask {
    position: absolute;
    z-index: 150;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: transparent;
  }
}
</style>
